Skip to content

feat!: normalize URL fields in responses - #1045

Merged
vdusek merged 5 commits into
v3from
feat/normalize-url-fields
Sep 9, 2026
Merged

vdusek merged 5 commits into
v3from
feat/normalize-url-fields

Conversation

@vdusek

@vdusek vdusek commented Sep 8, 2026

Copy link
Copy Markdown
Contributor

Fields the OpenAPI specification marks as format: uri are validated with z.url({ normalize: true }), so the client returns the WHATWG URL serialization rather than the raw string the API sent. The Python client normalizes the same fields through pydantic.AnyUrl, so both clients now return the same string for the same field. On the Python side that normalization was kept and documented in apify/apify-client-python#1005, and this PR follows the same decision.

Normalization adds a trailing slash to an empty path, lowercases and punycodes the host, drops a default port, and percent-encodes unsafe characters. The specification carries format: uri on 17 properties, none of them on request-queue requests. Field types stay string, and a value that isn't a valid absolute URL now throws ResponseValidationError. format: email is left as a plain string, since the issue is about URL fields.

The v3 upgrading guide gets a "URL fields are normalized" section mirroring the Python one: the normalization cases, how to compare a field against a stored URL, and the affected field names. The error-handling page points at it.

Closes #1028

✍️ Drafted by Claude Code

Fields the OpenAPI specification marks as `format: uri` are validated with
`z.url({ normalize: true })`, so the client hands back the WHATWG URL
serialization the way the Python client's `pydantic.AnyUrl` does, and the
two clients return the same string for the same field.

Closes #1028

BREAKING CHANGE: URL fields in responses (`containerUrl`, `consoleUrl`,
`standbyUrl`, `requestUrl`, `url`, `pictureUrl`, `userPictureUrl`,
`websiteUrl` and the `*PublicUrl` fields) come back normalized: an empty
path gains a trailing slash, the host is lowercased and punycoded, a
default port is dropped and unsafe characters are percent-encoded. A value
that is not a valid absolute URL now throws `ResponseValidationError`.
@vdusek vdusek added the t-tooling Issues with this label are in the ownership of the tooling team. label Sep 8, 2026
@vdusek vdusek self-assigned this Sep 8, 2026
@github-actions

github-actions Bot commented Sep 8, 2026 •

Copy link
Copy Markdown
Contributor

⚠️ There are broken links in the documentation.

See more at https://github.com/apify/apify-client-js/actions/runs/34338282630#summary-102422751439

@vdusek
vdusek requested a review from barjin September 9, 2026 08:56
@vdusek
vdusek marked this pull request as ready for review September 9, 2026 08:56
@vdusek
vdusek requested a review from szaganek as a code owner September 9, 2026 08:56

@barjin barjin left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

lgtm 👍 if we're already doing this in Python, I don't really see an issue here.

Thanks @vdusek !

@vdusek
vdusek merged commit 01f0d35 into v3 Sep 9, 2026
8 checks passed
@vdusek
vdusek deleted the feat/normalize-url-fields branch September 9, 2026 10:55
B4nan pushed a commit that referenced this pull request Sep 30, 2026
Fields the OpenAPI specification marks as `format: uri` are validated
with `z.url({ normalize: true })`, so the client returns the WHATWG URL
serialization rather than the raw string the API sent. The Python client
normalizes the same fields through `pydantic.AnyUrl`, so both clients
now return the same string for the same field. On the Python side that
normalization was kept and documented in apify/apify-client-python#1005,
and this PR follows the same decision.

Normalization adds a trailing slash to an empty path, lowercases and
punycodes the host, drops a default port, and percent-encodes unsafe
characters. The specification carries `format: uri` on 17 properties,
none of them on request-queue requests. Field types stay `string`, and a
value that isn't a valid absolute URL now throws
`ResponseValidationError`. `format: email` is left as a plain string,
since the issue is about URL fields.

The v3 upgrading guide gets a "URL fields are normalized" section
mirroring the Python one: the normalization cases, how to compare a
field against a stored URL, and the affected field names. The
error-handling page points at it.

Closes #1028

*✍️ Drafted by Claude Code*
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

t-tooling Issues with this label are in the ownership of the tooling team.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants